﻿using System;
using System.ComponentModel;
using System.ComponentModel.Design;
using System.Collections;
using System.Drawing;
using System.Linq;
using System.Workflow.ComponentModel;
using System.Workflow.ComponentModel.Design;
using System.Workflow.ComponentModel.Compiler;
using System.Workflow.ComponentModel.Serialization;
using System.Workflow.Runtime;
using System.Workflow.Activities;
using System.Workflow.Activities.Rules;

namespace WindowsWorkflow.SequentialActivities
{
	[ActivityValidator(typeof(PickValidator))]
	public partial class Pick : CompositeActivity
	{
		public Pick()
		{
			InitializeComponent();
		}

		#region dprops
		public static DependencyProperty FollowerOfProperty =
			DependencyProperty.RegisterAttached("FollowerOf", typeof(string), typeof(Pick),
			new PropertyMetadata(DependencyPropertyOptions.Metadata),
			typeof(FollowerOfAttachedPropertyValidator));

		public static object GetFollowerOf(object dependencyObject)
		{
			DependencyObject o = dependencyObject as DependencyObject;
			return o.GetValue(Pick.FollowerOfProperty);
		}

		public static void SetFollowerOf(object dependencyObject, object value)
		{
			DependencyObject o = dependencyObject as DependencyObject;
			o.SetValue(Pick.FollowerOfProperty, value);
		}
		#endregion

		#region props
		internal static bool IsLeader(Activity a)
		{
			return (Pick.GetFollowerOf(a) == null);
		}

		private bool firstLeaderDone;

		#endregion

		protected override void Initialize(IServiceProvider provider)
		{
			firstLeaderDone = false;
			base.Initialize(provider);
		}

		protected override ActivityExecutionStatus Execute(ActivityExecutionContext executionContext)
		{
			if (EnabledActivities.Count == 0)
				return ActivityExecutionStatus.Closed;

			foreach (Activity child in this.EnabledActivities)
			{
				if (Pick.IsLeader(child))
				{
					child.Closed += new EventHandler<ActivityExecutionStatusChangedEventArgs>(child_Closed);
					executionContext.ExecuteActivity(child);
				}
			}

			return ActivityExecutionStatus.Executing;
		}

		void child_Closed(object sender, ActivityExecutionStatusChangedEventArgs e)
		{
			e.Activity.Closed -= child_Closed;

			ActivityExecutionContext context = sender as ActivityExecutionContext;
			if (!firstLeaderDone)
			{
				// first leader is now completed
				firstLeaderDone = true;
				string leaderName = e.Activity.Name;
				// cancel the other leaders, if any
				int leadersCanceled = 0;
				foreach (Activity child in EnabledActivities)
				{
					if (child.ExecutionStatus == ActivityExecutionStatus.Executing)
					{
						context.CancelActivity(child);
						leadersCanceled++;
					}
				}

				// schedule execution of the followers, if any
				int followersExecuted = 0;
				foreach (Activity child in EnabledActivities)
				{
					string s = Pick.GetFollowerOf(child) as string;
					if (leaderName.Equals(s))
					{
						child.Closed += new EventHandler<ActivityExecutionStatusChangedEventArgs>(child_Closed);
						context.ExecuteActivity(child);
						followersExecuted++;
					}
				}

				if (leadersCanceled + followersExecuted == 0)
				{
					// no canceled leaders, and also no followers
					context.CloseActivity();
				}
			}
			else // a follower has completed
			{
				foreach (Activity child in EnabledActivities)
				{
					ActivityExecutionStatus status = child.ExecutionStatus;
					if (status != ActivityExecutionStatus.Closed && status != ActivityExecutionStatus.Initialized)
					{
						// there is still at least 1 follower executing 
						return;
					}
				}

				// all followers are done
				context.CloseActivity();
			}
		}
	}
}
